#pragma once
#include <etcd/Client.hpp>
#include <etcd/Response.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Watcher.hpp>
#include <thread>
#include <functional>
#include <memory>
#include "logger.hpp"

namespace my_im
{
    class Registry
    {
    public:
        using ptr = std::shared_ptr<Registry>;
        Registry(const std::string &host)
            : _client(std::make_shared<etcd::Client>(host)),
              _keepalive(_client->leasekeepalive(5).get()),
              _lease_id(_keepalive->Lease())
        {
        }

        ~Registry()
        {
            _keepalive->Cancel();
        }

        bool registry(const std::string &key, const std::string &val)
        {
            auto resp = _client->put(key, val, _lease_id).get();
            if (resp.is_ok() == false)
            {
                ERR("注册数据失败：{}", resp.error_message());
                return false;
            }
            return true;
        }

    private:
        std::shared_ptr<etcd::Client> _client;       // 客户端
        std::shared_ptr<etcd::KeepAlive> _keepalive; // 续租
        uint64_t _lease_id;                          // 保活id
    };

    class Discovery
    {
        using NotifyCallback = std::function<void(std::string, std::string)>;

    public:
        using ptr = std::shared_ptr<Discovery>;
        Discovery(const std::string &host,
                  const std::string &basedir,
                  const NotifyCallback &put_cb,
                  const NotifyCallback &del_cb)
            : _client(std::make_shared<etcd::Client>(host)), _put_cb(put_cb), _del_cb(del_cb)
        {
            // 进行当前数据的获取
            auto resp = _client->ls(basedir).get(); // 这里应该是ls
            if (resp.is_ok() == false)
            {
                ERR("获取数据服务失败：{}", resp.error_message());
            }
            for (int i = 0; i < resp.keys().size(); i++)
            {
                if (_put_cb)
                    _put_cb(resp.key(i), resp.value(i).as_string());
            }
            auto cb = std::bind(&Discovery::callback, this, std::placeholders::_1);
            _watcher = std::make_shared<etcd::Watcher>(host, basedir, cb, true);
        }

    private:
        void callback(etcd::Response resp)
        {
            for (auto const &ev : resp.events())
            {
                if (ev.event_type() == etcd::Event::EventType::PUT)
                {
                    // 数据发生改变
                    // std::cout << "添加服务器数据：" << std::endl;
                    // std::cout << "当前的值为" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl;
                    // std::cout << "原来的值为:" << ev.prev_kv().key() << "-" << ev.prev_kv().as_string() << std::endl;
                    if (_put_cb)
                        _put_cb(ev.kv().key(), ev.kv().as_string());
                    DBG("添加服务器数据:{}-{}", ev.kv().key(), ev.kv().as_string());
                }
                else if (ev.event_type() == etcd::Event::EventType::DELETE_)
                {
                    // std::cout << "服务信息下线被删除" << std::endl;
                    //  std::cout << "当前的值为" << ev.kv().key() << "-" << ev.kv().as_string() << std::endl;
                    //  std::cout << "原来的值为:" << ev.prev_kv().key() << "-" << ev.prev_kv().as_string() << std::endl;
                    if (_del_cb)
                        _del_cb(ev.kv().key(), ev.kv().as_string());
                    DBG("下线服务:{}-{}", ev.prev_kv().key(), ev.prev_kv().as_string());
                }
            }
        }

    private:
        NotifyCallback _put_cb;
        NotifyCallback _del_cb;
        std::shared_ptr<etcd::Client> _client;
        std::shared_ptr<etcd::Watcher> _watcher;
    };
}